package com.example.mansystem.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mansystem.component.AsyncTask;
import com.example.mansystem.dto.*;
import com.example.mansystem.entity.*;
import com.example.mansystem.mapper.*;
import com.example.mansystem.vo.*;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@Service
public class InstrumentService extends ServiceImpl<InstrumentMapper, InstrumentDO> {
    @Resource
    InstrumentMapper instrumentMapper;
    @Resource
    InstrumentExamineMapper instrumentExamineMapper;
    @Resource
    DegreeMapper degreeMapper;
    @Resource
    PlaceMapper placeMapper;
    @Resource
    ExamineInfoMapper examineInfoMapper;
    @Resource
    UserMapper userMapper;
    @Resource
    DepartmentMapper departmentMapper;
    @Resource
    ProcessMangerMapper processMangerMapper;
    @Autowired
    ActService actService;
    @Autowired
    WebSocketServer webSocketServer;
    @Autowired
    InstrumentEditCacheMapper instrumentEditCacheMapper;
    @Autowired
    AsyncTask asyncTask;
    @Autowired
    TaskService taskService;

    public HomeDataVO getHomeData()
    {
        long inNum=instrumentMapper.selectCount(null);
        long userNum =userMapper.selectCount(null);
        long placeNum=placeMapper.selectCount(null);
        long deNum=departmentMapper.selectCount(null);

        List<InstrumentExamineDO> list1=instrumentExamineMapper.selectList(null);
        LambdaQueryWrapper<ProcessMangerDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProcessMangerDO::getState,1);
        List<ProcessMangerDO> list2 = processMangerMapper.selectList(wrapper);

        return HomeDataVO.builder()
                .InNum(inNum)
                .deNum(deNum)
                .placeNum(placeNum)
                .userNum(userNum)
                .examList(list1)
                .processList(list2)
                .build();
    }

    public InPresentVO getInPresent()
    {
        ArrayList<ValNameVO> res1 =new ArrayList<>();
        Map<String,String> map1 = new HashMap<>();
        map1.put("1","数学");
        map1.put("2","力学");
        map1.put("3","物理学");
        map1.put("4","化学");
        map1.put("5","通讯");
        map1.put("6","生物学");
        LambdaQueryWrapper<InstrumentDO> wrapper = new LambdaQueryWrapper<>();
        for(Integer i=1;i<=6;i++)
        {
            wrapper.clear();
            wrapper.eq(InstrumentDO::getXKLY,i.toString());
            Long count1 =  instrumentMapper.selectCount(wrapper);
            res1.add(ValNameVO.builder().name(map1.get(i.toString()))
                    .value(count1)
                    .build());
        }

        ArrayList<ValNameVO> res3 =new ArrayList<>();
        Map<String,String> map3 = new HashMap<>();
        map3.put("1","教学");
        map3.put("2","科研");
        map3.put("3","行政");
        map3.put("4","生活与后勤");
        map3.put("5","生产");
        map3.put("6","技术开发");
        map3.put("7","社会服务");
        for(Integer i=1;i<=6;i++)
        {
            wrapper.clear();
            wrapper.eq(InstrumentDO::getSYFX,i.toString()).eq(InstrumentDO::getState,1);
            Long count3 =  instrumentMapper.selectCount(wrapper);
            res3.add(ValNameVO.builder().name(map3.get(i.toString()))
                    .value(count3)
                    .build());
        }

        wrapper.clear();
        wrapper.select(InstrumentDO::getSFBZ,InstrumentDO::getJE).eq(InstrumentDO::getState,1);
        List<Map<String, Object>> list4=instrumentMapper.selectMaps(wrapper);
        List<List<Integer>> res4=new ArrayList<>();
        long sfbzAvg=0;
        long jeAvg=0;
        int size=list4.size();
        for(int i=0;i<list4.size();i++)
        {
            List<Integer> temp=new ArrayList<>();
            Integer je=(Integer) list4.get(i).get("JE");
            Integer sfbz=(Integer) list4.get(i).get("SFBZ");
            sfbzAvg+=sfbz;
            jeAvg+=je;
            temp.add(je);
            temp.add(sfbz);
            res4.add(temp);
        }
        sfbzAvg/=size;
        jeAvg/=size;

        LambdaQueryWrapper<PlaceDO> placeDOQueryWrapper = new LambdaQueryWrapper<>();
        placeDOQueryWrapper.eq(PlaceDO::getPlaceType,0);
        List<PlaceDO> placeDOList=placeMapper.selectList(placeDOQueryWrapper);
        List<ListValNameVO> res2=new ArrayList<>();
        for(int i=0;i<placeDOList.size();i++)
        {
            Integer id=placeDOList.get(i).getPlaceId();
            wrapper.clear();
            wrapper.likeRight(InstrumentDO::getDepartmentId,id.toString()).eq(InstrumentDO::getState,1);
            long count=instrumentMapper.selectCount(wrapper);
            List<Double> temp=new ArrayList<>();
            temp.add(placeDOList.get(i).getLng());
            temp.add(placeDOList.get(i).getLat());
            temp.add((double)count);
            res2.add(ListValNameVO.builder().name(placeDOList.get(i).getPlaceName()).value(temp).build());
        }


        wrapper.clear();
        wrapper.eq(InstrumentDO::getState,1);
        long inCount=instrumentMapper.selectCount(wrapper);


       return InPresentVO.builder().list1(res1).list2(res2).list3(res3).list4(res4).jeAvg(jeAvg).sfbzAvg(sfbzAvg).inCount((int)inCount).placeCount(placeDOList.size()).build();
    }

    public PageInstrument getPageInstrument(PageInstrumentDto dto)
    {
        LambdaQueryWrapper<InstrumentDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(InstrumentDO::getState,1);
        for(int i=0;i<dto.getCondition().size();i++)
        {
            InstrumentConDto con=dto.getCondition().get(i);
            String text=con.getVal();
            int name=con.getCondition().get(0);
            int type=con.getCondition().get(1);
            switch (name) {
                case 1 -> {
                    switch (type) {
                        case 1 -> {
                            queryWrapper.eq(InstrumentDO::getYQMC, text);
                        }
                        case 2 -> {
                            queryWrapper.like(InstrumentDO::getYQMC, text);
                        }
                        case 3 -> {
                            queryWrapper.likeLeft(InstrumentDO::getYQMC, text);
                        }
                        case 4 -> {
                            queryWrapper.likeRight(InstrumentDO::getYQMC, text);
                        }
                    }
                }
                case 2 -> {
                    int YQBH = Integer.parseInt(text);
                    switch (type) {
                        case 1 ->{
                            queryWrapper.eq(InstrumentDO::getYQBH, YQBH);
                        }
                        case 2 ->{
                            queryWrapper.ne(InstrumentDO::getYQBH, YQBH);
                        }
                        case 3 ->{
                            queryWrapper.gt(InstrumentDO::getYQBH, YQBH);
                        }
                        case 4 ->{
                            queryWrapper.ge(InstrumentDO::getYQBH, YQBH);
                        }
                        case 5 ->{
                            queryWrapper.lt(InstrumentDO::getYQBH, YQBH);
                        }
                        case 6 ->{
                            queryWrapper.le(InstrumentDO::getYQBH, YQBH);
                        }
                    }
                }
                case 3 -> {
                    int money = Integer.parseInt(text);
                    switch (type) {
                        case 1 ->{
                            queryWrapper.eq(InstrumentDO::getJE, money);
                        }
                        case 2 ->{
                            queryWrapper.ne(InstrumentDO::getJE, money);
                        }
                        case 3 ->{
                            queryWrapper.gt(InstrumentDO::getJE, money);
                        }
                        case 4 ->{
                            queryWrapper.ge(InstrumentDO::getJE, money);
                        }
                        case 5 ->{
                            queryWrapper.lt(InstrumentDO::getJE, money);
                        }
                        case 6 ->{
                            queryWrapper.le(InstrumentDO::getJE, money);
                        }
                    }
                }
                case 4 -> {
                    int money = Integer.parseInt(text);
                    switch (type) {
                        case 1 ->{
                            queryWrapper.eq(InstrumentDO::getSFBZ, money);
                        }
                        case 2 ->{
                            queryWrapper.ne(InstrumentDO::getSFBZ, money);
                        }
                        case 3 ->{
                            queryWrapper.gt(InstrumentDO::getSFBZ, money);
                        }
                        case 4 ->{
                            queryWrapper.ge(InstrumentDO::getSFBZ, money);
                        }
                        case 5 ->{
                            queryWrapper.lt(InstrumentDO::getSFBZ, money);
                        }
                        case 6 ->{
                            queryWrapper.le(InstrumentDO::getSFBZ, money);
                        }
                    }
                }
                case 5 -> {
                    int number = Integer.parseInt(text);
                    switch (type) {
                        case 1 ->{
                            queryWrapper.eq(InstrumentDO::getPL, number);
                        }
                        case 2 ->{
                            queryWrapper.ne(InstrumentDO::getPL, number);
                        }
                        case 3 ->{
                            queryWrapper.gt(InstrumentDO::getPL, number);
                        }
                        case 4 ->{
                            queryWrapper.ge(InstrumentDO::getPL, number);
                        }
                        case 5 ->{
                            queryWrapper.lt(InstrumentDO::getPL, number);
                        }
                        case 6 ->{
                            queryWrapper.le(InstrumentDO::getPL, number);
                        }
                    }
                }
                case 6 -> {
                    queryWrapper.eq(InstrumentDO::getGXMS,type);
                }
                case 7 ->{
                    queryWrapper.eq(InstrumentDO::getXZ,type);
                }
                case 8 ->{
                    queryWrapper.eq(InstrumentDO::getXKLY,type);
                }
            }
        }
        Page<InstrumentDO> page = new Page<>(dto.getCurPage(),dto.getPageSize());
        IPage<InstrumentDO> iPage = instrumentMapper.selectPage(page,queryWrapper);
        return PageInstrument.builder().instrumentList(iPage.getRecords()).total((int)iPage.getTotal()).cur(dto.getCurPage()).build();
    }

    public void registerEdit(InstrumentRegisterEditDto dto)
    {
        InstrumentExamineDO instrumentExamineDO=instrumentExamineMapper.selectById(dto.getExamId());
        if(dto.getEdit()==0)
        {
            instrumentExamineMapper.deleteById(dto.getExamId());
            actService.notContinueEdit(instrumentExamineDO.getProcessId());
        }
        else if(dto.getEdit()==1)
        {
            InstrumentDO instrument = new InstrumentDO();
            BeanUtils.copyProperties(dto,instrument);
            instrument.setState(0);
            instrument.setYQBH(dto.getYQBH());
            instrumentMapper.updateById(instrument);
            actService.continueEdit(instrumentExamineDO.getProcessId(),dto.getJE());
        }
    }

    public void instrumentEdit(InstrumentEditDto dto)
    {
        InstrumentDO instrumentDO = instrumentMapper.selectById(dto.getYQBH());
        InstrumentCaCheDO instrumentCaCheDO = new InstrumentCaCheDO();
        BeanUtils.copyProperties(dto,instrumentCaCheDO);
        LambdaQueryWrapper<InstrumentCaCheDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(InstrumentCaCheDO::getYQBH,instrumentCaCheDO.getYQBH());
        long count = instrumentEditCacheMapper.selectCount(lambdaQueryWrapper);
        if(count==0)
        instrumentEditCacheMapper.insert(instrumentCaCheDO);
        else if(count>0)
            instrumentEditCacheMapper.updateById(instrumentCaCheDO);
        InstrumentExamineDO instrumentExamineDO = InstrumentExamineDO.builder().
                YQMC(instrumentDO.getYQMC()).
                username(dto.getUsername()).
                type(2).
                state(0).
                time(dto.getTime()).
                processId("-1").
                YQBH(dto.getYQBH()).build();
        instrumentExamineMapper.insert(instrumentExamineDO);
        String processId = actService.InstrumentEdit(dto,instrumentExamineDO.getId());
        instrumentExamineDO.setProcessId(processId);
        instrumentExamineMapper.updateById(instrumentExamineDO);
        Task list = taskService.createTaskQuery()
                .processInstanceId(processId)
                .singleResult();
        taskService.complete(list.getId());
    }

    public void batchRegister(String username, BatchInstrumentDto dto)
    {
        AtomicInteger curCount = new AtomicInteger();
        int size=dto.getBatchInstrument().size();
        curCount.set(0);
        for(Integer i=0;i<size;i+=1000)
        {
            if((i+999)<size)
            {
                asyncTask.AsyncInRegister(dto.getBatchInstrument().subList(i,i+1000),curCount,size,username,i);
            }
            else
            {
                asyncTask.AsyncInRegister(dto.getBatchInstrument().subList(i,size),curCount,size,username,i);
            }
        }
    }

    public void register(InstrumentRegisterDto dto)
    {
        InstrumentDO instrument = new InstrumentDO();
        BeanUtils.copyProperties(dto,instrument);
        instrument.setState(0);
        instrumentMapper.insert(instrument);
        InstrumentExamineDO instrumentExamineDO = InstrumentExamineDO.builder().
                YQMC(dto.getYQMC()).
                username(dto.getRegisterName()).
                type(1).
                state(0).
                time(dto.getRegisterTime()).
                processId("-1").
                YQBH(instrument.getYQBH()).build();
        instrumentExamineMapper.insert(instrumentExamineDO);
        String processId = actService.InstrumentRegister(dto,instrumentExamineDO.getId());
        instrumentExamineDO.setProcessId(processId);
        instrumentExamineMapper.updateById(instrumentExamineDO);
        Task list = taskService.createTaskQuery()
                .processInstanceId(processId)
                .singleResult();
        taskService.complete(list.getId());
    }

    public void deleteIn(DeleteInDto dto)
    {

        for(int i=0;i<dto.getInstrumentIdList().size();i++)
        {
            InstrumentExamineDO instrumentExamineDO = InstrumentExamineDO.builder().
                    YQBH(dto.getInstrumentIdList().get(i)).
                    YQMC(dto.getInNameList().get(i)).
                    username(dto.getUsername()).
                    type(3).
                    state(0).
                    time(dto.getTime()).
                    processId("-1").
                    build();
            instrumentExamineMapper.insert(instrumentExamineDO);
            String processId = actService.InstrumentDelete(dto,instrumentExamineDO.getId());
            instrumentExamineDO.setProcessId(processId);
            instrumentExamineMapper.updateById(instrumentExamineDO);
            Task list = taskService.createTaskQuery()
                    .processInstanceId(processId)
                    .singleResult();
            taskService.complete(list.getId());
        }
    }

    public ExamineInfo getAllExamineInfo(String roleName)
    {
        return actService.getListByRoleName(roleName);
    }


    public ExamineDegreeVO getExamineDegree()
    {
        DegreeDO register=degreeMapper.selectById(1);
        DegreeDO edit=degreeMapper.selectById(2);
        DegreeDO delete=degreeMapper.selectById(3);

        return ExamineDegreeVO.builder().register(register.getLel()).edit(edit.getLel()).delete(delete.getLel()).build();
    }

    public void changeExamineDegree(ExamineDegreeVO dto)
    {
        DegreeDO register=degreeMapper.selectById(1);
        DegreeDO edit=degreeMapper.selectById(2);
        DegreeDO delete=degreeMapper.selectById(3);

        register.setLel(dto.getRegister());
        edit.setLel(dto.getEdit());
        delete.setLel(dto.getDelete());

        degreeMapper.updateById(register);
        degreeMapper.updateById(edit);
        degreeMapper.updateById(delete);
    }

    public List<ExamineHisVO> getExamineHisByUsername(String username)
    {
        LambdaQueryWrapper<ExamineInfoDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ExamineInfoDO::getUsername,username);

        List<ExamineInfoDO> list = examineInfoMapper.selectList(wrapper);
        List<ExamineHisVO> res=new ArrayList<>();
        for(int i=0;i<list.size();i++)
        {
            ExamineInfoDO examineInfoDO = list.get(i);
            InstrumentExamineDO instrumentExamineDO = instrumentExamineMapper.selectById(examineInfoDO.getExamId());

            res.add(ExamineHisVO.builder().
                    id(examineInfoDO.getId()).examId(examineInfoDO.getExamId())
                    .username(username).registerName(instrumentExamineDO.getUsername())
                    .time(examineInfoDO.getTime()).pass(examineInfoDO.getPass()).YQMC(instrumentExamineDO.getYQMC())
                            .type(instrumentExamineDO.getType()).registerTime(instrumentExamineDO.getTime()).
                    build());
        }
        return res;
    }

}
